import { defineStore } from 'pinia'
import { ref, computed } from 'vue'

export const weekTitle = ['一', '二', '三', '四', '五', '六', '日']

export const courseTimeList = [
  { s: '08:00', e: '08:50' },
  { s: '08:55', e: '09:45' },
  { s: '10:15', e: '11:05' },
  { s: '11:10', e: '12:00' },
  { s: '14:00', e: '14:50' },
  { s: '14:55', e: '15:45' },
  { s: '16:15', e: '17:05' },
  { s: '17:10', e: '18:00' },
  { s: '19:00', e: '19:50' },
  { s: '19:55', e: '20:45' },
]

const colorMap = new Map()

// @unocss-include
export const colorList = [
  [
    '#FFDC72',
    '#CE7CF4',
    '#FF7171',
    '#66CC99',
    '#FF9966',
    '#66CCCC',
    '#6699CC',
    '#99CC99',
    '#669966',
    '#66CCFF',
    '#99CC66',
    '#FF9999',
    '#81CC74',
  ],
  [
    '#99CCFF',
    '#FFCC99',
    '#CCCCFF',
    '#99CCCC',
    '#A1D699',
    '#7397db',
    '#ff9983',
    '#87D7EB',
    '#99CC99',
  ],
]

const conflictCourseMap = new Map()

export const useCourseStore = defineStore('course', () => {
  const isStart = ref(false)
  const startDate = ref(new Date())
  const weekNum = ref(20)
  const courseList = ref([])
  const currentMonth = ref(0)
  const originalWeekIndex = ref(0)
  const currentWeekIndex = ref(0)
  const originalWeekWeekIndex = ref(new Date().getDay() === 0 ? 6 : new Date().getDay() - 1)
  const colorArrayIndex = ref(0)

  /**
   * set start date
   * @param someDate the start date of the semester
   */
  function setStartDay(someDate) {
    startDate.value = new Date(someDate)
    const days = new Date().getTime() - startDate.value.getTime()
    isStart.value = days > 0
    const week = Math.floor(days / (1000 * 60 * 60 * 24 * 7))
    originalWeekIndex.value = week < 0 ? 0 : week
    setCurrentWeekIndex(originalWeekIndex.value)
  }

  /**
   * change current week index
   * @param weekIndex the new week index
   */
  function setCurrentWeekIndex(weekIndex) {
    conflictCourseMap.clear()
    currentWeekIndex.value = weekIndex
    // change current month
    const someDate = new Date(startDate.value)
    someDate.setDate(someDate.getDate() + weekIndex * 7)
    currentMonth.value = someDate.getMonth() + 1
  }

  /**
   * init course list
   * @param newCourseList new course list
   */
  function setCourseList(newCourseList) {
    conflictCourseMap.clear()
    // sort by week and start
    courseList.value = newCourseList.sort((a, b) => a.week - b.week || a.start - b.start)
    resetCourseBgColor()
  }

  // current week course list
  const weekCourseList = computed(() => {
    if (courseList.value)
      return courseList.value.filter((item) => item.weeks.includes(currentWeekIndex.value + 1))
    return []
  })

  // data for course action
  const parsedCourseList = computed(() => {
    // init a course array
    const parsedCourseList = Array.from({ length: weekNum.value }, () =>
      Array.from({ length: 7 }, () => Array.from({ length: 5 }, () => 0)),
    )

    if (courseList.value) {
      // process course list
      for (const courseItem of courseList.value) {
        const { start, duration, week, weeks } = courseItem
        for (const w of weeks) {
          const dayCourseList = parsedCourseList[w - 1][week - 1]
          dayCourseList[Math.floor(start / 2)]++
          // some courses may last more than 2 times
          if (duration > 2) dayCourseList[Math.floor(start / 2 + 1)]++
        }
      }
    }
    return parsedCourseList
  })

  // current week date list
  const currentWeekDayArray = computed(() => {
    const weekIndex = currentWeekIndex.value
    const someDate = new Date(startDate.value)
    someDate.setDate(someDate.getDate() + weekIndex * 7)
    const dayArray = []
    dayArray.push(someDate.getDate())
    for (let i = 0; i < 6; i++) {
      someDate.setDate(someDate.getDate() + 1)
      dayArray.push(someDate.getDate())
    }
    return dayArray
  })

  /**
   * list of course for a certain course item time
   * @param courseItem the course item
   */
  function getConflictCourse(courseItem) {
    if (!courseItem) return []
    const { week, start } = courseItem
    return courseList.value.filter((item) => {
      return (
        item.weeks.includes(currentWeekIndex.value + 1) &&
        item.week === week &&
        item.start === start
      )
    })
  }

  /**
   * list of course for a certain course item time with map
   * @param courseItem the course item
   */
  function hasConflictCourseByMap(courseItem) {
    if (!conflictCourseMap.has(courseItem))
      conflictCourseMap.set(courseItem, getConflictCourse(courseItem))
    return conflictCourseMap.get(courseItem) || []
  }

  /**
   * reset course bg color
   */
  function resetCourseBgColor() {
    colorMap.clear()
    if (courseList.value) {
      courseList.value.map((courseItem) =>
        Object.assign(courseItem, { color: getCourseColor(courseItem) }),
      )
    }
  }

  /**
   * get course item color
   * @param courseItem course item
   * @returns course color
   */
  function getCourseColor(courseItem) {
    const colorArray = colorList[colorArrayIndex.value]
    const { title } = courseItem
    if (!colorMap.has(title)) colorMap.set(title, colorArray[colorMap.size % colorArray.length])
    return colorMap.get(title) || 'bg-white'
  }

  watch(
    () => colorArrayIndex.value,
    () => resetCourseBgColor(),
  )

  /**
   * set a course to top when there have more than one course in the same time
   * @param courseItem course item
   */
  function setCourseItemTop(courseItem) {
    deleteCourseItem(courseItem)
    courseList.value.unshift(courseItem)
  }

  /**
   * delete a course
   * @param courseItem course item
   */
  function deleteCourseItem(courseItem) {
    conflictCourseMap.clear()
    const { title, week, start } = courseItem
    for (let i = 0; i < courseList.value.length; i++) {
      const item = courseList.value[i]
      if (item.title === title && item.week === week && item.start === start)
        courseList.value.splice(i, 1)
    }
  }

  /**
   * delete a course by title
   * @param courseTitle course title
   */
  function deleteCourseItemByTitle(courseTitle) {
    conflictCourseMap.clear()
    for (let i = 0; i < courseList.value.length; i++) {
      const item = courseList.value[i]
      if (item.title === courseTitle) courseList.value.splice(i, 1)
    }
  }

  return {
    isStart,
    startDate,
    weekNum,
    currentMonth,
    courseList,
    setCourseList,
    weekCourseList,
    parsedCourseList,
    originalWeekIndex,
    currentWeekIndex,
    originalWeekWeekIndex,
    currentWeekDayArray,
    colorArrayIndex,
    setStartDay,
    setCurrentWeekIndex,
    getConflictCourse,
    hasConflictCourseByMap,
    setCourseItemTop,
    deleteCourseItem,
    deleteCourseItemByTitle,
  }
})
